﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Resources;
using System.Text;
using System.Collections;
using System.Xml;
using System.Reflection;
using System.Xml.Linq;
using EBA.Helpers;
using System.Threading;

namespace EBA.Localization
{
    /// <summary>
    /// Resx文件形式的本地化翻译
    /// </summary>
    public class ResxLocalizationProvider : ILocalizationProvider
    {

        string _ResourcePath;
        /// <summary>
        /// 数据库地址，以XML形式
        /// </summary>
        string ResourcePath
        {
            get
            {
                if (this._ResourcePath.HasValue() == false)
                {
                    var directory = Path.Combine(AppRuntime.ApplicationPath, "I18N");

                    if (!Directory.Exists(directory))
                    {
                        Directory.CreateDirectory(directory);
                    }
                    this._ResourcePath = directory;
                }

                return this._ResourcePath;
            }
        }

        private string EmptyContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                              "<root>" +
                              "<xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">" +
                              "<xsd:element name=\"root\" msdata:IsDataSet=\"true\">" +
                              "<xsd:complexType>" +
                              "<xsd:choice maxOccurs=\"unbounded\">" +
                              "<xsd:element name=\"data\">" +
                              "<xsd:complexType>" +
                              "<xsd:sequence>" +
                              "<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />" +
                              "<xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />" +
                              "</xsd:sequence>" +
                              "<xsd:attribute name=\"name\" type=\"xsd:string\" msdata:Ordinal=\"1\" />" +
                              "<xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />" +
                              "<xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />" +
                              "</xsd:complexType>" +
                              "</xsd:element>" +
                              "<xsd:element name=\"resheader\">" +
                              "<xsd:complexType>" +
                            "<xsd:sequence>" +
                                "<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />" +
                            "</xsd:sequence>" +
                            "<xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />" +
                        "</xsd:complexType>" +
                    "</xsd:element>" +
                "</xsd:choice>" +
            "</xsd:complexType>" +
        "</xsd:element>" +
    "</xsd:schema>" +
    "<resheader name=\"resmimetype\">" +
        "<value>text/microsoft-resx</value>" +
    "</resheader>" +
    "<resheader name=\"version\">" +
        "<value>1.3</value>" +
    "</resheader>" +
    "<resheader name=\"reader\">" +
        "<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>" +
    "</resheader>" +
    "<resheader name=\"writer\">" +
        "<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>" +
    "</resheader>" +
"</root>";



        /// <summary>
        /// 翻译
        /// </summary>
        /// <param name="key"></param>
        /// <param name="culture"></param>
        /// <param name="defaultText"></param>
        /// <returns></returns>
        public string Translate(string key, CultureInfo culture, string defaultText = null)
        {
            var resourceFile = Path.Combine(this.ResourcePath, "Resources_" + culture.Name + ".resx");
            string value = key;
            if (defaultText != null)
            {
                value = defaultText;
            }
            if (!File.Exists(resourceFile))
            {
                value = FindParent(key, culture, value);
                CreateResource(resourceFile);
                Add(key, resourceFile, value);
                return value;
            }
            else
            {
                var tempt = GetValue(key, resourceFile);
                if (tempt != null)
                {
                    value = tempt;
                }
                else
                {
                    value = FindParent(key, culture, value);
                    Add(key, resourceFile, value);
                }
                return value;
            }
        }


        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="key"></param>
        /// <param name="culture"></param>
        /// <param name="defaultText"></param>
        public void Update(string key, CultureInfo culture, string defaultText)
        {
            var resourceFile = Path.Combine(this.ResourcePath, "Resources_" + culture.Name + ".resx");
            var reader = new ResXResourceReader(resourceFile);
            var nodes = reader.Cast<DictionaryEntry>();
            using (var writer = new ResXResourceWriter(resourceFile))
            {
                foreach (var node in nodes)
                {
                    if ((string)node.Key == key)
                    {
                        writer.AddResource(new ResXDataNode((string)node.Key, defaultText));
                    }
                    else
                    {
                        writer.AddResource(new ResXDataNode((string)node.Key, node.Value));
                    }
                }
                writer.Generate();
                writer.Close();
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="key"></param>
        /// <param name="culture"></param>
        public void Delete(string key, CultureInfo culture)
        {
            var resourceFile = Path.Combine(this.ResourcePath, "Resources_" + culture.Name + ".resx");
            var reader = new ResXResourceReader(resourceFile);
            var nodes = reader.Cast<DictionaryEntry>();
            using (var writer = new ResXResourceWriter(resourceFile))
            {
                foreach (var node in nodes)
                {
                    if (node.Key.ToString() != key)
                    {
                        writer.AddResource(new ResXDataNode((string)node.Key, node.Value));
                    }
                }
                writer.Generate();
                writer.Close();
            }
        }


        /// <summary>
        /// 获得RESX形式的所有文化
        /// </summary>
        /// <returns></returns>
        public IEnumerable<CultureInfo> GetCultures()
        {
            List<CultureInfo> cultures = null;
            if (Directory.Exists(ResourcePath))
            {
                var directoryInfo = new DirectoryInfo(ResourcePath);
                cultures = new List<CultureInfo>();
                foreach (var file in directoryInfo.GetFiles())
                {
                    var culture = CultureInfo.GetCultureInfo(Path.GetFileNameWithoutExtension(file.Name).Split('_')[1]);
                    if (culture != null)
                    {
                        cultures.Add(culture);
                    }
                }
            }
            return cultures;
        }

        /// <summary>
        /// 获得对应文化的所有主键
        /// </summary>
        /// <param name="culture"></param>
        /// <returns></returns>
        public IEnumerable<string> GetKeys(CultureInfo culture = null)
        {
            if (culture == null)
            {
                culture = Thread.CurrentThread.CurrentUICulture;
            }
            var resourceFile = Path.Combine(this.ResourcePath, "Resources_" + culture.Name + ".resx");
            if (File.Exists(resourceFile))
            {
                var reader = new ResXResourceReader(resourceFile);
                var keys = new List<string>();
                foreach (DictionaryEntry node in reader)
                {
                    keys.Add(node.Key.ToString());
                }
                return keys;
            }
            return null;
        }


        /// <summary>
        /// 获得指定文化所对应主键的文本值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public string GetTextValue(string key, CultureInfo culture = null)
        {
            if (culture == null)
            {
                culture = Thread.CurrentThread.CurrentUICulture;
            }
            var resourceFile = Path.Combine(this.ResourcePath, "Resources_" + culture.Name + ".resx");
            return GetValue(key, resourceFile);
        }


        #region 内部实现方法


        private void Add(string key, string file, string defaultText)
        {
            var reader = new ResXResourceReader(file);
            var nodes = reader.Cast<DictionaryEntry>();
            using (var writer = new ResXResourceWriter(file))
            {
                foreach (var node in nodes)
                {
                    writer.AddResource(new ResXDataNode((string)node.Key, node.Value));
                }
                var newnode = new ResXDataNode(key, defaultText);
                writer.AddResource(newnode);
                writer.Generate();
                writer.Close();
            }
        }


        private static XmlNode GetNode(XmlDocument xmlDoc, string key)
        {
            XmlNodeList xnlist = xmlDoc.GetElementsByTagName("data");
            foreach (XmlNode node in xnlist)
            {
                if (node.Attributes != null)
                {
                    if (node.Attributes["xml:space"].Value == "preserve")
                    {
                        if (node.Attributes["name"].Value == key)
                        {
                            return node;
                        }
                    }
                }
            }
            return null;
        }


        private string FindParent(string key, CultureInfo culture, string defaultvalue = null)
        {
            string value = defaultvalue;
            if (culture.Parent.Name.HasValue())
            {
                var file = Path.Combine(this.ResourcePath, "Resources_" + culture.Parent.Name);
                if (File.Exists(file))
                {
                    value = GetValue(key, file);
                    if (value != null)
                    {
                        return value;
                    }
                }
                return FindParent(key, culture.Parent, value);
            }
            return value;
        }

        private static string GetValue(string key, string resourceFile)
        {
            string value = null;
            var read = new ResXResourceReader(resourceFile);
            foreach (DictionaryEntry node in read)
            {
                if (node.Key.ToString() == key)
                {
                    read.Close();
                    value = (string)node.Value;
                }
            }
            return value;
        }

        private void CreateResource(string resourceFile)
        {
            var stream = File.Create(resourceFile);
            var file = new StreamWriter(stream);
            file.Write(EmptyContent);
            file.Flush();
            file.Close();
        }
        #endregion
    }
}
